/**
  * @(#)MeetingTime.java
  *
  * Wrap the java.util.Date class in a manner better suited for the scheduler
  * 	than java.sql.Time
  *
  * @author Course Scheduler Team
  * 
  * @license GNU General Public License version 3 (GPLv3)
  *
  * This file is part of Course Scheduler, an open source, cross platform
  * course scheduling tool, configurable for most universities.
  *
  * Copyright (C) 2010-2012 Course Scheduler Team
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  * 
  */
package com.pollicitus.scheduler.model;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import com.pollicitus.scheduler.model.ConcretelyAnnouncable;
import com.pollicitus.scheduler.model.MeetingTime;

/**
 * Implement the section meeting times by wrapping java.util.Date 
 * 	in an appropriate manner
 * 
 * @author Course Scheduler Team
 *
 */
public class MeetingTime implements ConcretelyAnnouncable {

	/**
	 * The most recent revision in which this file was changed in the source control system
	 */
	public static final String _revision = "$LastChangedRevision: 539 $";
	
	/**
	 * The date on which this file was last changed and submitted to source control
	 */
	public static final String _date = "$LastChangedDate: 2011-11-19 23:14:16 -0500 (Sat, 19 Nov 2011) $";
	
	/**
	 * The user which last changed the file and committed the change to source control
	 */
	public static final String _author = "$LastChangedBy: mike@pollicitus.com $";
	
	/**
	 * The URL which can be used to access this specific file within the source control system
	 */
	public static final String _headURL = "$HeadURL: https://courseschedulerx.googlecode.com/svn/trunk/course-scheduler/course-scheduler-core/src/main/java/com/pollicitus/scheduler/model/MeetingTime.java $";
	
	/**
	 * The source control file ID, comprised of the file name, latest revision, last changed date, and submitting user.
	 */
	public static final String _id = "$Id: MeetingTime.java 539 2011-11-20 04:14:16Z mike@pollicitus.com $";
	
	//class static field
	private static final long serialVersionUID = 1L;
	private static final String TBA = "TBA";
	private static final String defaultFormat1 = "hh:mm";
	private static final String defaultFormat2 = "hh:mm a";
	private static final String militaryFormat1 = "HH:mm";
	private static final String militaryFormat2 = "HH:mm";
	private static final String defaultSeparator = "-";
	
	//private class variables
	private boolean tba = false;
	private Date startTime;
	private Date endTime;
	
	/**
	 * Default constructor to prep the Date objects
	 */
	public MeetingTime(){
		startTime = new Date();
		endTime = new Date();
	}
	
	
	/**
	 * Build the Meeting Time and specify if the meeting time is concrete
	 * 
	 * @param tba if the meeting time is "to be announced"
	 */
	public MeetingTime(boolean tba) {
		this();
		
		this.tba = tba;
	}
	
	/**
	 * Construct the meeting time using the specified start and end times
	 * 
	 * @param startTime the meeting start time
	 * @param endTime the meeting end time
	 */
	public MeetingTime(Date startTime, Date endTime) {
		this.startTime = startTime;
		this.endTime = endTime;
	}
	
	/* (non-Javadoc)
	 * @see java.util.Date#toString()
	 */
	@Override
	public String toString(){
		return toString(defaultFormat1, defaultSeparator, defaultFormat2);
	}
	
	/**
	 * Return the meeting time as a string in 24 hour format
	 * 
	 * @return the Meeting time in 24 hour format
	 */
	public String toString24Hour(){
		return toString(militaryFormat1, defaultSeparator, militaryFormat2);
	}
	
	/**
	 * @see java.lang.String#toString()
	 * 
	 * Return the meeting time as a string using the specified formats
	 * 
	 * @param startFormat
	 * @param separator
	 * @param endFormat
	 * @return the string in the specified format
	 */
	public String toString(String startFormat, String separator, String endFormat){
		if(tba) return TBA;
		return new SimpleDateFormat(startFormat).format(startTime) + separator + new SimpleDateFormat(endFormat).format(endTime);
	}
	
	/* (non-Javadoc)
	 * @see com.scheduler.model.Concretable#isConcrete()
	 */
	public boolean isConcretelyAnnounced() {
		return !tba;
	}
	
	/*
	 * @param time
	 * @return a meeting time parsed from the input string using default parse values
	 * @throws IllegalArgumentException
	 */
	public static MeetingTime parseTime(String time)throws IllegalArgumentException{
		return parseTime(time, defaultFormat1, defaultFormat2, defaultSeparator);
	}
	
	/**
	 * Parse the start and end times and return a new MeetingTime based on the
	 * parsed values
	 * 
	 * @param startTime the start time string to parse
	 * @param endTime the end time string to parse
	 * @param startFormat the string format to use for the start time
	 * @param endFormat the string format to use for the end time
	 * @return the meeting time parsed from the input using the format strings
	 * @throws IllegalArgumentException if the parsing parameters are invalid
	 */
	public static MeetingTime parseTime(String startTime, String endTime, String startFormat, String endFormat) throws IllegalArgumentException{
		Date start, end;
		try{
			start = parseTime(startTime, startFormat);
			end = parseTime(endTime, endFormat);
		}catch(ParseException e){
			throw new IllegalArgumentException(e);
		}
		return new MeetingTime(start, end);
	}

	/**
	 * Parse the specified time using the specified parsing format and return a date
	 * 
	 * @param time the time string to parse
	 * @param format the time format string to use while parsing
	 * @return the parsed Time in the form of a date
	 * @throws ParseException if the simple date format cannot parse the time
	 */
	public static Date parseTime(String time, String format) throws ParseException{
		return new SimpleDateFormat(format).parse(time);
	}

	/* (non-Javadoc)
	 * @see com.scheduler.model.Announcable#isUnAnnounced()
	 */
	public boolean isToBeAnnounced() {
		return !isConcretelyAnnounced();
	}
	
	/**
	 * Return if the specified time is valid for use as a time
	 * 
	 * @param time the date to validate
	 * @return if the time is valid
	 */
	public static boolean validateTime(Date time){
		Calendar validate = new GregorianCalendar();
		validate.setTime(time);
		
		//validate against epoch for the date
		return validate.get(Calendar.YEAR) == 1970 &&
				validate.get(Calendar.MONTH) == Calendar.JANUARY &&
				validate.get(Calendar.DAY_OF_MONTH) == 1;
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object o){
		MeetingTime other = (MeetingTime)o;
		
		return other.tba == this.tba &&
				other.endTime.compareTo(this.endTime) == 0 &&
				other.startTime.compareTo(this.startTime) == 0;
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode(){
		return endTime.hashCode() ^
				startTime.hashCode();
	}
}
